package be.humphreys.simplevoronoi;

import java.util.ArrayList;
import java.util.HashMap;

import com.jellyfishumbrella.Corner;
import com.jellyfishumbrella.Site;

public class Cell {
	public ArrayList<GraphEdge>	edges;
	public Site					site;
	public boolean				checked	= false;
	public ArrayList<Float[]>	glTriangleFan;

	public Cell() {
		edges = new ArrayList<GraphEdge>();
	}

	public boolean isWater() {
		return (((LandscapeSite) site).isLake || ((LandscapeSite) site).isOcean);
	}

	public Cell findUncheckedNeighbor(HashMap<Site, Cell> cells) {
		for (int i = 0; i < edges.size(); i++) {
			GraphEdge currEdge = edges.get(i);
			if (currEdge.site1 != site && !cells.get(currEdge.site1).checked) {
				return cells.get(currEdge.site1);
			} else if (currEdge.site2 != site && !cells.get(currEdge.site2).checked) {
				return cells.get(currEdge.site2);
			}
		}
		return null;
	}

	public void confirmEdgeLoop() {
		float EPSILON = 0.1f;
		GraphEdge currEdge = edges.get(0);
		Corner first, next, prev;
		first = prev = currEdge.corner1;
		next = currEdge.corner2;

		System.out.print(prev.glID + "   " + next.glID + "   ");
		while (next != first) {
			for (int i = 0; i < edges.size(); i++) {
				GraphEdge testEdge = edges.get(i);
				if (testEdge != currEdge) {
					float delta1x = (float) Math.abs(testEdge.corner1.x - next.x);
					float delta1y = (float) Math.abs(testEdge.corner1.y - next.y);
					float delta2x = (float) Math.abs(testEdge.corner2.x - next.x);
					float delta2y = (float) Math.abs(testEdge.corner2.y - next.y);

					//if ((delta1x < EPSILON && delta1y < EPSILON) && testEdge.corner1 != prev && testEdge.corner2 != prev) {
					//	prev = next;
						if ((delta1x < EPSILON && delta1y < EPSILON)) {
							prev = next;
							testEdge.corner1 = next;
							next = testEdge.corner2;
							currEdge = testEdge;
							break;
						} else if ((delta2x < EPSILON && delta2y < EPSILON)) {
							prev = next;
							testEdge.corner2 = next;
							next = testEdge.corner1;
							currEdge = testEdge;
							break;
						}
					//}
				}
			}
			System.out.print(next.glID + "   ");
			if (prev == next) {
				System.out.println("stop");
			}
		}
		System.out.println();
	}

	public void makeTriangleFan() {
		glTriangleFan = new ArrayList<Float[]>();
		//glTriangleFan.add(new Float[] { (float) site.x, (float) site.alt, (float) site.y });

		GraphEdge currEdge = edges.get(0);
		Corner first, next, prev;
		float[] normal = computeTriangleNormal(currEdge);

		float dotProduct = normal[0] * 0 + normal[1] * 1 + normal[2] * 0;
		if (dotProduct > 0) {
			first = edges.get(0).corner2;
			prev = first;
			next = edges.get(0).corner1;
			glTriangleFan.add(new Float[] { (float) currEdge.corner2.x, (float) currEdge.corner2.alt, (float) currEdge.corner2.y });
		} else {
			first = edges.get(0).corner1;
			prev = first;
			next = edges.get(0).corner2;
			glTriangleFan.add(new Float[] { (float) currEdge.corner1.x, (float) currEdge.corner1.alt, (float) currEdge.corner1.y });
		}

		System.out.println(glTriangleFan.get(0)[0] + "   " + glTriangleFan.get(0)[1] + "   " + glTriangleFan.get(0)[2]);

		int index = 0;

		while (next != first) {// interesting ... some edges have a single
								// corner for both corner1 and corner2... and
								// loop is broken
			index++;
			for (int i = 0; i < next.edges.size(); i++) {
				GraphEdge testEdge = next.edges.get(i);
				if ((testEdge.site1 == site || testEdge.site2 == site) && testEdge.corner1 != prev && testEdge.corner2 != prev) {
					prev = next;
					if (testEdge.corner1 == next) {
						next = testEdge.corner2;
					} else {
						next = testEdge.corner1;
					}
				}
			}
			glTriangleFan.add(new Float[] { (float) next.x, (float) next.alt, (float) next.y });

			System.out.println(glTriangleFan.get(index)[0] + "   " + glTriangleFan.get(index)[1] + "   " + glTriangleFan.get(index)[2]);

			if (glTriangleFan.size() > edges.size()) {
				System.out.println("-----------------------------triangleFan: " + glTriangleFan.size() + "   " + edges.size());
				return;
			}
		}
		System.out.println("-----------------------------triangleFan: " + glTriangleFan.size() + "   " + edges.size());
	}

	public void pointNormalsUp() {
		for (int i = 0; i < edges.size(); i++) {
			GraphEdge currEdge = edges.get(i);
			float[] normal = computeTriangleNormal(currEdge);
			float dotProduct = normal[0] * 0 + normal[1] * 1 + normal[2] * 0;
			if (dotProduct < 0) {
				Corner temp = currEdge.corner1;
				currEdge.corner1 = currEdge.corner2;
				currEdge.corner2 = temp;
				--i;
			}
		}
	}

	public float[] computeTriangleNormal(GraphEdge currEdge) {
		Corner a = new Corner();// normals
		Corner b = new Corner();// normals

		float[] normal = new float[3];
		normal[0] = 0.0f;
		normal[1] = 0.0f;
		normal[2] = 0.0f;

		a.x = currEdge.corner1.x - site.x;
		//a.alt = currEdge.corner1.alt - site.alt;
		a.y = currEdge.corner1.y - site.y;

		b.x = currEdge.corner2.x - site.x;
		//b.alt = currEdge.corner2.alt - site.alt;
		b.y = currEdge.corner2.y - site.y;

		normal[0] = (float) (b.alt * a.y - b.y * a.alt);
		normal[1] = (float) (b.y * a.x - b.x * a.y);
		normal[2] = (float) (b.x * a.alt - b.alt * a.x);

		normalize(normal);
		return normal;
	}

	public void computeNormal() {

		float[] avgNormal = new float[3];
		avgNormal[0] = 0.0f;
		avgNormal[1] = 0.0f;
		avgNormal[2] = 0.0f;

		for (int i = 0; i < edges.size(); i++) {
			GraphEdge currEdge = edges.get(i);
			float[] normal = computeTriangleNormal(currEdge);

			// float dotProduct = normal[0] * 0 + normal[1] * 1 + normal[2] * 0;
			// if (dotProduct < 0) {
			// Corner temp = currEdge.corner1;
			// currEdge.corner1 = currEdge.corner2;
			// currEdge.corner2 = temp;
			// --i;
			// } else {
			avgNormal[0] += normal[0];
			avgNormal[1] += normal[1];
			avgNormal[2] += normal[2];
			// }
		}

		avgNormal[0] /= edges.size();
		avgNormal[1] /= edges.size();
		avgNormal[2] /= edges.size();

		normalize(avgNormal);

		//site.normal = avgNormal;
	}

	public void normalize(float[] origNormal) {
		float mag = (float) Math.sqrt(origNormal[0] * origNormal[0] + origNormal[1] * origNormal[1] + origNormal[2] * origNormal[2]);
		if (mag != 0.0f) {
			origNormal[0] /= mag;
			origNormal[1] /= mag;
			origNormal[2] /= mag;
		} else {
			origNormal[0] = 0.0f;
			origNormal[1] = 1.0f;
			origNormal[2] = 0.0f;
		}
	}

	public void computeGLCorners() {

	}
}
